CSGBox

CSG nodes are helpful for building props and prototyping levels

Constructive solid geometry (CSG) nodes let us use boolean operations to create exciting shapes to prototype 3D levels and props directly in the editor.

For example, we can use a CSGCylinder with three sides to create an extrusion of a regular triangle:

Or, we can use CSGCylinder’s Cone property to generate a cone:

By altering these properties, we can create many interesting shapes to use in prototype levels:

After we finish prototyping, we can export our scene as glTF for further development in external 3D modeling software. This feature is new in Godot v3.4.

Given these limitations, we prepared a couple of demos to showcase CSG nodes and their practical uses. In this tutorial, you’ll learn:

In addition, we cover recommendations and tips for helping you get the most out of these nodes.

Contents:

Key features and properties of CSG nodes

The primary purpose of CSG nodes is to combine them to make interesting shapes. However, nothing stops us from just using them for their easy customization.

Keeping your CSG trees shallow is highly advisable as Godot generates CSG meshes procedurally. This process is resource-intensive and not designed for real-time updates.

Among all the CSG nodes, two stand out:

These nodes make it easy for us to customize them in the 3D viewport through mouse interaction; an option that MeshInstance doesn’t provide.

All CSG nodes inherit from the CSGShape class. This class holds the common properties for CSG nodes, including CSGCombiner.

Operation

We can set the Operation property to one of three regular boolean operations:

  1. Union: merge geometry to the largest common volume, removing intersecting volumes.
  2. Intersection: only intersecting volumes remain.
  3. Subtraction: children’s volumes get subtracted from the parent’s volume.

This property works by processing the child nodes and their operations in tree order and applying them to itself.

Here’s a showcase of these operations:

The image above is a result of a basic scene structure with a CSGBox node as a parent with two CSGCylinder nodes as children:

Each column showcases the result of setting both CSGCylinder nodes Operation property to Union, Intersection, and Subtraction. The CSGBox Operation property is only relevant if it’s a child of another CSG node.

Snap

The CSGShape’s Snap property makes meshes snap to a given distance so that the faces of two meshes align precisely for the boolean operations.

Calculate Tangents

The Calculate Tangents property is only relevant for the root shape. This property is on by default. It allows for the use of normal maps.

Use Collision

The Use Collision property appears in the Inspector on the top-most CSG node. If true, this property informs Godot to calculate a collision shape for the physics engine based on the resulting CSG mesh. This shape acts as a static body and is active even if the CSG node’s visibility is off. Switching on this property results expands the Inspector with additional options for selecting the collision layer and mask:

Invert Faces

One inheritance step below CSGShape is CSGPrimitive. This is a parent class for all CSG nodes that generate geometries. All CSG nodes except CSGCombiner have this property.

We go over using this property when appropriate while showcasing each CSG node.

Smooth Faces

Most CSG nodes share the Smooth Faces property. We can find it on CSGCylinder, CSGPolygon, CSGSphere, and CSGTorous. This property blends between adjacent faces based on their normals with this property turned on. We can see the effect of this setting better on a CSGSphere. In the following image, we have Smooth Faces turned off on the left and turned on to the right:

The blending gives the right shape a rounder look, even though both images have the same geometry.

Material

The Material property appears on all CSG nodes other than CSGCombiner, which doesn’t hold a mesh. With this property, we can assign custom SpatialMaterial or ShaderMaterial resources, just like we would with a MeshInstance. The difference with a MeshInstance is that we don’t control UVs on CSG nodes.

Given that Godot generates the UVs for us, we can turn on the SpatialMaterial’s Uv1 -> Triplanar mapping setting. In short, triplanar mapping projects a texture onto the mesh from three different angles and attempts to blend them to reduce apparent seams.

We use the CSGCylinder node and a test texture for this presentation:

We have a scene with three CSGCylinder nodes as follows:

We control the triplanar mapping using the Inspector settings under the SpatialMaterial’s Uv 1 section: Scale, Offset, and Triplanar Sharpness which modifies the blending between faces.

A useful option on SpatialMaterial Flags -> World Triplanar. This option makes triplanar mapping work in world coordinates rather than local coordinates.

The World Triplanar option makes the projection planes align with the global world coordinates rather than the local ones. We can understand this better by viewing the following image:

The left cylinder keeps the texture aligned with its local transform because we haven’t turned on World Triplanar, unlike the one to the right.

That was a quick overview of how CSG nodes support SpatialMaterial resources. However, you may not need advanced setups like these for fast prototypes.

For an in-depth look at shaders, we recommend our Shader Secrets: Learn to Code 2D and 3D Shaders in Godot course:

Exporting your mesh

From Godot v3.4, you can now export your mesh to external 3D programs using the glTF file format. It allows you to prototype environments in Godot and later refine them in another program like Blender.

To export your scene as glTF, click on Project -> Tools -> Export GLTF….

Looking at the main CSG nodes

We grouped all CSG nodes in this guide as they all work together. In this section, we look at what each node does.

CSGBox

The CSGBox node gives us a customizable box mesh.

We can control its properties in the Inspector:

Or, we can control it through the viewport, where the handles are a visual aid for the Width, Height, and Depth settings:

The Invert Faces property, inherited from CSGPrimitive, is useful for creating volumes that we can see inside of:

This screen capture shows the before and after turning on Invert Faces. Initially, the box looks solid, but after turning on Invert Faces, we see inside of it.

This effect happens because the default SpatialMaterial assigned to these nodes has Parameters -> Cull Mode set to Back.

If we set Cull Mode to Front, the inverse effect would happen, and we’d see inside the box when turning off Invert Faces.

The last option for disabling Cull Mode renders the box solid, regardless the Invert Faces property.

CSGCylinder

The CSGCylinder node gives us more than cylinders to work with, depending on how many Sides we set and if we turn on the Cone property.

We can manipulate it in the 3D viewport with the help of the handles:

Or directly from the Inspector:

The minimum amount of sides is three.

The Cone property gives us a cone-shaped mesh. The Radius property applies to the larger side. Here are a few variations that this node can give us:

CSGMesh

The CSGMesh node gives us the ability to combine custom meshes imported from external 3D software:

We need an *.obj file for assigning it to the Mesh property:

There are a few requirements for the mesh to work properly:

This custom mesh example meets all these requirements:

We look at this custom mesh more in the level prototyping demo.

CSGPolygon

The CSGPolygon node lets us define a polygon figure in the XY plane that we can use in three modes: Depth, Spin, and Path.

We can construct the polygon manually in the Inspector through the Polygon property, with a minimum of three points:

Another option is to construct the XY polygon in the 3D viewport using visual tools.

We can create points with CTRL + Left Click and drag them to new positions.

The created polygon snaps automatically to the XY plane.

CSGPolygon depth mode

In Mode -> Depth, we can use the Depth property to extrude the polygon along the Z-axis:

CSGPolygon spin mode

Here’s a visual presentation of what customizing the polygon looks like with Mode -> Spin:

This mode gives us a different set of properties to adjust the constructed object:

We have a Spin Degree option that sets the amount of rotation the polygon makes around the Y-axis. Here’s an example with Spin Degree set to 140:

Spin Sides defines how many sides we generate during the spin process. A lower value results in a low-poly spin, while a higher value gives us more geometry.

Here’s an example of the above profile set to a Spin Sides value of 32, instead of the default 8:

CSGPolygon path mode

Next, we look at Mode -> Path. Again, we can use the same process of modifying the XY polygon visually.

We can tell Godot to extrude the profile along a curve defined through the Path node in this mode.

Setting the Mode -> Path updates the Inspector to reflect path-related options:

We must assign a node to the Path Node property since the Path node could be anywhere in the scene tree.

To have a smooth workflow with Mode -> Path, try keeping the CSGPolygon profile centered around the node’s origin or within one of the quadrants while starting at the origin. This example showcases the two setups:

Following this recommendation, it’s a lot easier to predict the placement of the 3D extrusion.

Note that this doesn’t apply to Mode -> Spin since we might want to spin around the Y-axis at a distance:

The Path Interval Type property defines how Path Interval behaves. It can be set to either Distance or Subdivide. Path Interval defines the distance between extrusions.

We have two CSGPolygon nodes using the same Path node that spans 2 units to exemplify the differences. Both CSGPolygon nodes have Path Interval set to 0.5. The difference is that we set Path Interval Type -> Distance on the left one, while the right one to Path Interval Type -> Subdivide.

We can see how faces are extruded at intervals of 0.5 units in the left case while the right has 3 extrusions, irrespective of the Path span.

Path Interval Type -> Distance is an absolute setting that makes CSGPolygon extrude at regular intervals, while we use Path Interval Type -> Subdivide to set a given number of subdivisions instead.

When working with Path Interval Type -> Distance, try using the same value for Path’s Curve -> Bake Interval property as CSGPolygon’s Path Interval. In most cases, this produces the best results.

In the following example, we keep the Bake Interval to its default value of 0.2 and vary the Path Interval going from left-to-right with these values: 0.1, 0.2, 0.5, 1.0.

Setting Path Interval to a lower value than Bake Interval doesn’t necessarily produce better results, so more resolution doesn’t mean better in this case. A lower resolution improves performance in heavy scenes.

The following property, Path Simplify Angle, lets us simplify the mesh by merging extrusions when the angle is smaller than the one set in the Inspector.

For example, we can see how this setting would greatly reduce the number of extrusions when dealing with long stretches of unchanging angles:

The Path Simplify Angle property is a massive help with performance.

Path Rotation has several modes:

Given that we don’t have control over the Curve orientation, it might be difficult to get the desired result, so you’ll have to experiment with the settings:

Path Local lets us select the profile extrusion location. If Path Local is off, the extrusion happens on the curve. Otherwise, it starts relative to the CSGPolygon location:

Path Continuous U and Path U Distance give us some control over how textures apply to the CSGPolygon extrusions:

In this demonstration, we use the same test texture from before:

Note that in the CSGPolygon extrusion to the left, each face takes the same UV square space, repeating the image with every extrusion step.

We have Path Continuous U turned on to the right, which repeats the image every meter by default. We can change this distance using the Path U Distance parameter.

Notice how the CSGPolygon uses the texture. The texture’s top half gets mapped along the extrusions, while the bottom part gets cut in two halves and mapped to the caps.

Finally, we have the last Path-related property called Path Joined. It joins the caps of the CSGPolygon:

CSGSphere

The CSGSphere node is the simplest CSG mesh. It’s a sphere with one control point that updates the Radius.

Additionally, we can change the Radius from in the Inspector:

We also have additional settings:

CSGTorus

The CSGTorus, or donut, has an inner and outer radius. We can change these through the visual handles or from the Inspector:

The Inner Radius and Outer Radius properties are conventions. The Inner Radius can be larger than the Outer Radius without any issues:

The other properties are:

CSGCombiner

The CSGCombiner node is a special node used to organize our scene. It doesn’t hold any mesh data itself. It also doesn’t have any properties other than the ones inherited from CSGShape:

To showcase how it works, we compare two setups with the same result, one of them with CSGCombiner:

The two CSG trees under Spatial result in identical volumes. The one to the right is using CSGCombiner.

The CSGCombiner node can keep the CSG trees shallow to improve performance.

How to use CSG nodes in practice

We look at a couple of examples of using the CSG nodes in practice for level prototyping and constructing walkable paths using the CSGPolygon in combination with a Path node.

A distinct feature of these demos is that they have no code for CSG nodes specifically. Everything is in the 3D editor.

Constructing a level prototype

When constructing level prototypes, it’s essential to keep CSGMesh meshes as simple as possible because slow performance is the number one issue when working with CSG nodes.

This example showcases the creation of a level prototype by carving rooms with corridors inside a custom mesh.

To construct the interior of the mountain, we turn on CSGMesh’s Invert Faces property so we can visualize the interior of the volume:

We can minimize the performance hit when working with CSG nodes by combining them into chunks as needed. For example, here we work under the CSGCombiner node separately for constructing the bulk of the mountain carving:

Then, we make it a child of the CSGMesh node:

This brings us to our final carving result:

We also construct a few reusable components like a placeholder statue, decorative windows, and symbols:

Not all CSG trees combine through boolean operations. For example, the decorative window has this scene tree, with a Spatial node at the root:

Not performing the boolean operations results in better performance. Only use the boolean operations if necessary.

We need the boolean operations to construct the decorative symbol since we use it to carve inside the mountain as part of the room. This scene tree has a CSGBox node for root to take advantage of the Subtraction boolean operator.

Once we are done laying out the rooms and corridors, we then add objects like ramps, stairs, and any other necessary parts:

Remember to turn on Use Collision for the required nodes to have the player and environment interact with one another:

Adding the other decorations gives us the final result:

Solid paths with CSGPolygon

This example showcases the use of CSGPolygon in Path mode to create walkways between game islands in a 3D platformer type game:

Unlike the previous demo, where we use CSG nodes to combine them into more complex objects through boolean operations, we use CSGPolygon to construct final objects for real-time use. We can do this because we aren’t using heavy boolean operators to combine objects.

We constructed a few islands using the GridMap node and connected them using path constructed with CSGPolygon and Path nodes:

The objective is to get to the coin on the island on the far end of the map. This requires that we construct walkways. We use a CSGPolygon set to path mode, where both the Curve’s Bake Interval and CSGPolygon’s Path Interval are 0.5 to get a reasonably smooth-looking geometry.

We use a Path Simplify Angle value of 1 to cut down on the unnecessary geometry and set Path Rotation to Path so that the walkways always have a flat top surface.

We have a custom material that repeats a seamless texture to integrate the paths with the GridMap visuals.

The texture image is a one-pixel vertical slice of this repeating pattern:

This creates repeating slices along the paths by having a repeated pattern along the X-axis. This axis is in the same direction as U in the context of shader terminology.

We get this final result for one of the walkways:

Remember to turn on Use Collision to get player-paths interaction:

For a thorough explanation on how to use the GridMap node, check out the GridMap guide.

Pro tips

This section lists a few recommendations that you might want to try when working with CSG nodes for a better development experience.

These aren’t hard rules, so try and experiment until you find a workflow that suits your style.

Viewport grids

The 3D ground (XZ plane) divides into a one-by-one meters grid. You can turn on XY and YZ grids in the Editor -> Editor Settings… panel, along with other options related to the grid:

When designing CSGPolygon profiles, it might be helpful to turn on the XY grid temporarily. This grid is represented by gray lines:

Display tools

In some cases, it’s helpful to work in Orthogonal or Display Overdraw mode depending on the complexity of your scene. We find these visual modes in the viewport menu from the top-left corner.

CSG Subtraction materials

The resulting materials for the holes come from the subtracted object when performing the subtraction operation.

For example, we subtract a small CSGBox with a red material from a bigger CSGBox with the default white material resulting in the hole becoming red:

CSGPolygon quadrant for spin mode

When working in the spin mode, keep the CSGPolygon profile in the positive X quadrant, that is, in the orange-shaded part of the axis.

Due to how Godot constructs the geometry in this mode, the boolean operations will fail if we don’t keep to the positive X quadrant:

In the following image, we can see how the Union operation produces bad geometry:

Instead, use rotation and translation to get the desired orientation, so Godot combines the objects correctly.

A better way to join CSGPolygon end caps

When constructing circular paths with CSGPolygon in path mode, it isn’t enough to switch Path Joined on if the curve itself isn’t closed:

After closing the curve, you might have to massage the handles and end cap points slightly to get the desired result. At this point, it’s safe to turn on Path Joined to get the final geometry:

CSGPolygon Path Interval limit

The Path Interval Property is clamped in the interval [0, 1]. If for some reason, you want to go above 1, you can do so by:

Don’t go above 1 when working with Path Interval Type -> Subdivide.

CSGPolygon Path Local gotcha

When working with Path Local turned off, make sure to keep the CSGPolygon location at Vector3(0, 0, 0). This keeps the location around the world origin. Otherwise, the translation factors into the location of the final mesh, and it won’t align with the location of the Path:

You might expect to see the extrusion align with the Path node to the left, but it doesn’t because the CSGPolygon location isn’t at the world origin, as you can see by checking the move gizmo.

CSGPolygon-Path Z axis gotcha

When working with Path Rotation set to either Polygon or Path, make sure that the curve used for extrusion decreases along the Z-axis. Otherwise, we end up with an unusable mesh:

The one to the left has Path Rotation set to Polygon. The one on the right is set to Path.

CSGPolygon PathFollow gotcha

When we check Up Vector -> Enabled, Godot calculates the orientation of the Path’s Curve automatically for us.

When working with CSGPolygon in path mode and Path Rotation set to PathFollow, remember to turn on Up Vector -> Enabled. Otherwise, the CSGPolygon behaves as if Path Rotation is set to Path mode instead.

Visual artifacts

When working with the CSG nodes, parenting and moving the nodes around might result in visual artifacts in the 3D viewport.

If this happens to you, an easy fix is to save your scene first and click on Scene -> Reload Saved Scene from the menu, forcing the viewport to reset:

Be careful with this option. Save your changes first!